package edu.ua.cs.cs515.gcj.tetris;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.RenderingHints;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.awt.image.BufferedImage;

import javax.swing.JPanel;

/**
 * The main view for the tetris game
 */
public class TetrisView extends JPanel implements KeyListener, MouseMotionListener, MouseListener {
	
	// Define some constants for our button
	private final int START_GAME = 0;
	private final int PAUSE_GAME = 1;
	private final int RESUME_GAME = 2;
	
	// The current scene
	private BufferedImage scene = null;
	private BufferedImage buffer = null;
	
	private Graphics2D sceneg = null;
	
	// The tetris controller
	private TetrisController controller;

	// The views width and height
	private int viewHeight = 0;
	private int viewWidth = 0;
	
	// A rectangle area where the button will be drawn
	private Rectangle buttonArea;
	
	// Custome blue color
	private Color LightBlue = new Color(0x0066FF);
	
	// Is true if the mouse pointer is over the button, false otherwise
	private boolean mouseOverButton = false;
	
	// The current button type
	private int buttonType = START_GAME;
		
	// Constructor, accepts a tetris controller
	public TetrisView(TetrisController controller) {
		
		this.setFocusable(true);
		this.requestFocus();
		this.controller = controller;
		this.addKeyListener(this);
		this.addMouseListener(this);
		this.addMouseMotionListener(this);
		this.setDoubleBuffered(true);
		
	}
	
	// Sets the area to be occupied by the button
	public void setButtonArea(Rectangle buttonArea) {
		this.buttonArea = buttonArea;
		repaint();
	}
	
	public void resetButton() {
		buttonType = START_GAME;
		repaint();
	}
	
	// Returns a reference to the graphics object of the current scene
	// We will be double buffering to avoid flickering
	public Graphics2D getSceneGraphcs() {
		if (scene == null || scene.getWidth() != this.getViewWidth() || scene.getHeight() != this.getViewHeight()) {
			this.scene = new BufferedImage(this.getViewWidth(), this.getViewHeight(), BufferedImage.TYPE_INT_ARGB);
			this.buffer = new BufferedImage(this.scene.getWidth(), this.scene.getHeight(), BufferedImage.TYPE_INT_ARGB);
		}
		this.sceneg = scene.createGraphics();
		this.sceneg.setBackground(this.getBackground());
		return this.sceneg;
	}
	
	public void render() {
		Graphics2D bufd = this.buffer.createGraphics();
		// Draw the image to the buffer and repaint
		bufd.drawImage(this.scene, 0, 0, this);
		repaint();
		bufd.dispose();
	}
	
	// Repaint the component until the view width has been set
	// Returns the views width
	public int getViewWidth() {
		while (this.viewWidth == 0) {
			repaint();
		}
		return this.viewWidth;
	}
	
	// Repaint the component until the view height has been set
	// Return the views height
	public int getViewHeight() {
		while (this.viewHeight == 0) {
			repaint();
		}
		return this.viewHeight;
	}
	
	// Draws the scene and the button onto the componenet
	public void paintComponent(Graphics g) {
		super.paintComponent(g);
		Graphics2D g2d = (Graphics2D)g;

		this.viewHeight = this.getHeight();
		this.viewWidth = this.getWidth();
		
		// Draw the buffer to the panel
		if (buffer != null) {
			g2d.drawImage(this.buffer, 0, 0, this);
		}
		
		// Draw the button
		if (buttonArea != null) {
			String buttonText = "";
			if (!mouseOverButton) {
				g2d.setColor(LightBlue);
			} else {
				g2d.setColor(LightBlue.brighter());
			}
			g2d.fillRect(buttonArea.x, buttonArea.y, buttonArea.width, buttonArea.height);
			g2d.setColor(Color.GRAY);
			g2d.drawRect(buttonArea.x, buttonArea.y, buttonArea.width, buttonArea.height);
			g2d.setColor(Color.WHITE);
			g2d.drawRect(buttonArea.x+1, buttonArea.y+1, buttonArea.width-2, buttonArea.height-2);
			switch (buttonType) {
			case START_GAME:
				buttonText = "Start Game";
				break;
			case PAUSE_GAME:
				buttonText = "Pause Game";
				break;
			case RESUME_GAME:
				buttonText = "Resume Game";
				break;
			}
			g2d.setColor(Color.WHITE);
			Font font = g2d.getFont();
			g2d.setFont(new Font(font.getName(),font.getStyle(),24));
			int stringWidth = g2d.getFontMetrics().stringWidth(buttonText);
			g2d.drawString(buttonText, (float)buttonArea.getCenterX() - stringWidth/2, (float)buttonArea.getCenterY() + g2d.getFontMetrics().getHeight()/4);
		}
		g2d.dispose();
	}

	// Handles the keyReleased event.  Unsets the speed up if the user releases the down key
	@Override
	public void keyReleased(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_DOWN) {
			controller.unSetSpeedUp();
		}
	}

	// Handles the keyPressed event.  Moves the tetromino, rotates the tetromino or sets
	// the speed up depending on the key which is pressed.
	@Override
	public void keyPressed(KeyEvent e) {
		if (e.getKeyCode() == KeyEvent.VK_LEFT) {
			controller.moveLeft();
		} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
			controller.moveRight();
		} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
			controller.setSpeedUp();
		} else if (e.getKeyCode() == KeyEvent.VK_UP) {
			controller.rotate();
		} else if (e.getKeyCode() == KeyEvent.VK_SPACE) {
			controller.dropBlock();
		}
	}
	
	// Handles the mouseClicked event.  If the used clicks over the button ares then
	// call the appropriate method in the controller for starting, pausing or resuming
	@Override
	public void mouseClicked(MouseEvent evt) {
		if (mouseOverButton) {
			if (buttonType == START_GAME) {
				buttonType = PAUSE_GAME;
				controller.startGame();
				Main.difficultyMenu.setEnabled(false);
			} else if (buttonType == PAUSE_GAME) {
				buttonType = RESUME_GAME;
				controller.pauseResume();
			} else if (buttonType == RESUME_GAME) {
				buttonType = PAUSE_GAME;
				controller.pauseResume();
			}
		}
	}
	
	// Handles the mouseMoved event.  If the user moves the mouse over the button we
	// want to change the cursor to a hand and set the mouseOverButton boolean so that
	// we can draw the button appropriately.
	@Override
	public void mouseMoved(MouseEvent evt) {
		if (buttonArea != null) {
			if (buttonArea.contains(evt.getPoint())) {
				this.setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
				if (!mouseOverButton) {
					mouseOverButton = true;
					repaint(buttonArea);
				}
			} else {
				this.setCursor(Cursor.getDefaultCursor());
				if (mouseOverButton) {
					mouseOverButton = false;
					repaint(buttonArea);
				}
			}
		}
	}
	
	
	// We don't use the following event handlers
	@Override
	public void keyTyped(KeyEvent evt) {
		// Unused
	}


	@Override
	public void mouseEntered(MouseEvent evt) {
		// Unused
	}

	@Override
	public void mouseExited(MouseEvent evt) {
		// Unused
	}

	@Override
	public void mousePressed(MouseEvent evt) {
		// Unused
	}

	@Override
	public void mouseReleased(MouseEvent evt) {
		// Unused
	}

	@Override
	public void mouseDragged(MouseEvent evt) {
		// Unused	
	}

}
